package com.atguigu.gulimall.order.service.impl;

import com.atguigu.common.exception.NoStockException;
import com.atguigu.common.to.es.SkuHasStockVo;
import com.atguigu.common.vo.MemberRsepVo;
import com.atguigu.gulimall.order.contant.OrderConstant;
import com.atguigu.gulimall.order.entity.OmsOrderItemEntity;
import com.atguigu.gulimall.order.enume.OrderStatusEnum;
import com.atguigu.gulimall.order.feign.AddressFeign;
import com.atguigu.gulimall.order.feign.CartFeign;
import com.atguigu.gulimall.order.feign.ProductFeignService;
import com.atguigu.gulimall.order.feign.WareFeign;
import com.atguigu.gulimall.order.interceptor.LoginUserInterceptor;
import com.atguigu.gulimall.order.service.OmsOrderItemService;
import com.atguigu.gulimall.order.to.OrderCreateTo;
import com.atguigu.gulimall.order.vo.*;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.order.dao.OmsOrderDao;
import com.atguigu.gulimall.order.entity.OmsOrderEntity;
import com.atguigu.gulimall.order.service.OmsOrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;


@Service("omsOrderService")
public class OmsOrderServiceImpl extends ServiceImpl<OmsOrderDao, OmsOrderEntity> implements OmsOrderService {
    @Resource
    AddressFeign addressFeign;
    @Resource
    CartFeign cartFeign;
    @Resource
    private ThreadPoolExecutor executor;
    @Resource
    private WareFeign wareFeign;
    @Resource
    private ProductFeignService productFeignService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    OmsOrderItemService orderItemService;

    private ThreadLocal<OderSubmitVo> submitOrderThreadLocal=new ThreadLocal<>();
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OmsOrderEntity> page = this.page(
                new Query<OmsOrderEntity>().getPage(params),
                new QueryWrapper<OmsOrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo toTrade() throws ExecutionException, InterruptedException {
        MemberRsepVo userInfoTo = LoginUserInterceptor.threadLocal.get();
        RequestAttributes attributes= RequestContextHolder.getRequestAttributes();
        OrderConfirmVo orderConfirmVo=new OrderConfirmVo();
        //查询地址
        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(attributes);
            List<AddressVo> addressList = addressFeign.list(userInfoTo.getId());
            orderConfirmVo.setAddressList(addressList);
        }, executor);


        //购物车
        CompletableFuture<Void> cartFuture = CompletableFuture.supplyAsync(() -> {
            RequestContextHolder.setRequestAttributes(attributes);
            List<CartItemVo> cartItemVos = cartFeign.currentUserCartItems();
            orderConfirmVo.setCartItemList(cartItemVos);
            return cartItemVos;
        }, executor).thenAcceptAsync((res)->{
            List<Long> skuIds = res.stream().map((e) -> {return e.getSkuId();}).collect(Collectors.toList());
            List<SkuHasStockVo> skuHasStock = wareFeign.getSkuHasStock(skuIds);
            if(skuHasStock!=null){
                Map<Long, Boolean> map = skuHasStock.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
                orderConfirmVo.setHasStockMap(map);
            }
        },executor);

        //生成令牌
        String random=(Math.random() + 1) * 100000000+"";
        String orderToken= System.currentTimeMillis()+random.substring(2,random.length());
        System.out.println("token---------------------"+orderToken);
        stringRedisTemplate.opsForValue().set(OrderConstant.ORDER_TOKEN+":"+userInfoTo.getId(),orderToken,30, TimeUnit.MINUTES);
        CompletableFuture.allOf(addressFuture,cartFuture).get();
        //积分
        Integer integration = userInfoTo.getIntegration();
        orderConfirmVo.setIntegration(integration);
        orderConfirmVo.setOrderToken(orderToken);
        return orderConfirmVo;
    }

    @Transactional
    @Override
    public SubmitOrderResponseVo submitOrder(OderSubmitVo oderSubmitVo) {
        submitOrderThreadLocal.set(oderSubmitVo);
        SubmitOrderResponseVo submitOrderResponseVo=new SubmitOrderResponseVo();
        MemberRsepVo userInfoTo = LoginUserInterceptor.threadLocal.get();
        /**
         * 校验重复令牌   1. 验证令牌 [必须保证原子性] 返回 0 or 1
         * 0 令牌删除失败 1删除成功
         */
        String s = stringRedisTemplate.opsForValue().get(OrderConstant.ORDER_TOKEN + ":" + userInfoTo.getId());
        String token=oderSubmitVo.getOrderToken();
        String script = "if redis.call('get',KEYS[1]) == ARGV[1]" +
                "then return redis.call('del',KEYS[1]) " +
                "else return 0 " +
                "end";
        Long execute = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(OrderConstant.ORDER_TOKEN + ":" + userInfoTo.getId()), token);
        if(execute==1L){
            //校验成功,执行后续逻辑
            OrderCreateTo orderCreateTo=createOrderTo(userInfoTo.getId());
            //锁定库存
            WareSkuLockVo wareSkuLockVo=new WareSkuLockVo();
            wareSkuLockVo.setOrderSn(orderCreateTo.getOrder().getOrderSn());
            List<CartItemVo> collect = orderCreateTo.getOrderItems().stream().map(o -> {
                CartItemVo cartItemVo = new CartItemVo();
                cartItemVo.setSkuId(o.getSkuId());
                cartItemVo.setCount(o.getSkuQuantity());
                cartItemVo.setTitle(o.getSkuName());
                return cartItemVo;
            }).collect(Collectors.toList());
            wareSkuLockVo.setCartItemVoList(collect);
            //保存订单信息
            saveOrder(orderCreateTo);
            //调用库存服务锁库存
            Boolean lockFlag = wareFeign.lockStock(wareSkuLockVo);
            if(lockFlag){
                submitOrderResponseVo.setCode(0);
                submitOrderResponseVo.setOrderEntity(orderCreateTo.getOrder());
            }else{
                throw new NoStockException("库存不足");
            }
            return submitOrderResponseVo;
        }else{
            submitOrderResponseVo.setCode(2);
            return submitOrderResponseVo;
        }
    }

    private void saveOrder(OrderCreateTo orderCreateTo) {
        this.save(orderCreateTo.getOrder());
        List<OmsOrderItemEntity> orderItemEntityList=orderCreateTo.getOrderItems();
        orderItemEntityList.stream().map(orderItem->{
            orderItem.setOrderId(orderCreateTo.getOrder().getId());
            return orderItem;
        }).collect(Collectors.toList());
        orderItemService.saveBatch(orderItemEntityList);
    }

    public OrderCreateTo createOrderTo(Long memberId) {
        OrderCreateTo orderCreateTo=new OrderCreateTo();
        String orderSn= IdWorker.getTimeId();
        // 填充订单的各种基本信息，价格信息
        OmsOrderEntity omsOrderEntity = buildOrder(orderSn);
        omsOrderEntity.setMemberId(memberId);
        orderCreateTo.setOrder(omsOrderEntity);

        // 2. 获取所有订单项   // 从里面已经设置好了用户该使用的价格
        List<OmsOrderItemEntity> orderItems=buildOrderItems(orderSn);
        orderCreateTo.setOrderItems(orderItems);

        // 3.根据订单项计算价格	传入订单 、订单项 计算价格、积分、成长值等相关信息
        computerPrice(omsOrderEntity, orderItems);
        return orderCreateTo;
    }

    /**
     * 验价  传入订单（包含了优惠券等，最终价格也要放到他里面）和订单项
     */
    private void computerPrice(OmsOrderEntity orderEntity, List<OmsOrderItemEntity> items) {

        // 叠加每一个订单项的金额
        BigDecimal coupon = new BigDecimal("0.0");
        BigDecimal integration = new BigDecimal("0.0");
        BigDecimal promotion = new BigDecimal("0.0");
        BigDecimal gift = new BigDecimal("0.0");
        BigDecimal growth = new BigDecimal("0.0");

        // 总价
        BigDecimal totalPrice = new BigDecimal("0.0");
        for (OmsOrderItemEntity item : items) {  // 这段逻辑不是特别合理，最重要的是累积总价，别的可以跳过
            // 优惠券的金额
            coupon = coupon.add(item.getCouponAmount());
            // 积分优惠的金额
            integration = integration.add(item.getIntegrationAmount());
            // 打折的金额
            promotion = promotion.add(item.getPromotionAmount());
            BigDecimal realAmount = item.getRealAmount();
            totalPrice = totalPrice.add(realAmount);

            // 购物获取的积分、成长值
            gift.add(new BigDecimal(item.getGiftIntegration().toString()));
            growth.add(new BigDecimal(item.getGiftGrowth().toString()));
        }
        // 1.订单价格相关 总额、应付总额
        orderEntity.setTotalAmount(totalPrice);
        orderEntity.setPayAmount(totalPrice.add(orderEntity.getFreightAmount()));

        orderEntity.setPromotionAmount(promotion);
        orderEntity.setIntegrationAmount(integration);
        orderEntity.setCouponAmount(coupon);

        // 设置积分、成长值
        orderEntity.setIntegration(gift.intValue());
        orderEntity.setGrowth(growth.intValue());

        // 设置订单的删除状态
        orderEntity.setDeleteStatus(OrderStatusEnum.CREATE_NEW.getCode());
    }


    //构建订单列表list
    private List<OmsOrderItemEntity> buildOrderItems(String orderSn) {
        List<OmsOrderItemEntity> orderItems=null;
        List<CartItemVo> cartItemVos = cartFeign.currentUserCartItems();
        if(cartItemVos!=null && cartItemVos.size()>0){
            orderItems = cartItemVos.stream().map(cartItemVo -> {
                OmsOrderItemEntity itemEntity = buildOrderItem(cartItemVo);
                itemEntity.setOrderSn(orderSn);
                return itemEntity;
            }).collect(Collectors.toList());
        }
        return orderItems;
    }


    //
    private OmsOrderItemEntity buildOrderItem(CartItemVo cartItem) {
        /**
         * 构建某一个订单项
         */ // OrderServiceImpl
            OmsOrderItemEntity itemEntity = new OmsOrderItemEntity();
            // 1.订单信息： 订单号
            // 已经在items里设置了

            // 2.商品spu信息
            Long skuId = cartItem.getSkuId();
            // 远程获取spu的信息
            SpuInfoVo spuInfo = productFeignService.spuInfoBySkuId(skuId);
            itemEntity.setSpuId(spuInfo.getId());
            itemEntity.setSpuBrand(spuInfo.getBrandId().toString());
            itemEntity.setSpuName(spuInfo.getSpuName());
            itemEntity.setCategoryId(spuInfo.getCatalogId());

            // 3.商品的sku信息
            itemEntity.setSkuId(cartItem.getSkuId());
            itemEntity.setSkuName(cartItem.getTitle());
            itemEntity.setSkuPic(cartItem.getImage());
            itemEntity.setSkuPrice(cartItem.getPrice());
            // 把一个集合按照指定的字符串进行分割得到一个字符串
            // 属性list生成一个string
            String skuAttr = StringUtils.collectionToDelimitedString(cartItem.getAttr(), ";");
            itemEntity.setSkuAttrsVals(skuAttr);
            itemEntity.setSkuQuantity(cartItem.getCount());
            // 4.积分信息 买的数量越多积分越多 成长值越多
            itemEntity.setGiftGrowth(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())).intValue());
            itemEntity.setGiftIntegration(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())).intValue());

            // 5.订单项的价格信息 优惠金额
            itemEntity.setPromotionAmount(new BigDecimal("0.0")); // 促销打折
            itemEntity.setCouponAmount(new BigDecimal("0.0")); // 优惠券
            itemEntity.setIntegrationAmount(new BigDecimal("0.0")); // 积分

            // 当前订单项的原价
            BigDecimal orign = itemEntity.getSkuPrice().multiply(new BigDecimal(itemEntity.getSkuQuantity().toString()));
            // 减去各种优惠的价格
            BigDecimal subtract =
                    orign.subtract(itemEntity.getCouponAmount()) // 优惠券逻辑没有写，应该去coupon服务查用户的sku优惠券
                            .subtract(itemEntity.getPromotionAmount()) // 官方促销
                            .subtract(itemEntity.getIntegrationAmount()); // 京豆/积分
            itemEntity.setRealAmount(subtract);
            return itemEntity;
    }

    //构建order
    public OmsOrderEntity buildOrder(String orderSn){
        OmsOrderEntity omsOrderEntity=new OmsOrderEntity();
        omsOrderEntity.setOrderSn(orderSn);
        omsOrderEntity.setCreateTime(new Date());
        omsOrderEntity.setCommentTime(new Date());
        omsOrderEntity.setReceiveTime(new Date());
        omsOrderEntity.setDeliveryTime(new Date());
        OderSubmitVo oderSubmitVo = submitOrderThreadLocal.get();
        AddressVo addressVo = addressFeign.getAddressById(oderSubmitVo.getAddrId());
        omsOrderEntity.setReceiverName(addressVo.getName());
        omsOrderEntity.setReceiverPhone(addressVo.getPhone());
        omsOrderEntity.setReceiverPostCode(addressVo.getPostCode());
        omsOrderEntity.setReceiverProvince(addressVo.getProvince());
        omsOrderEntity.setReceiverCity(addressVo.getCity());
        omsOrderEntity.setReceiverRegion(addressVo.getRegion());
        omsOrderEntity.setReceiverDetailAddress(addressVo.getDetailAddress());
        omsOrderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        omsOrderEntity.setAutoConfirmDay(7);//自动确认收货
        return omsOrderEntity;


    }


}